<template>
  <!--
      如何在同一组建中展现表示不同的样式
      1、html表示整个布局的结构，具体的展示样式，将有css决定
      2、每种展示样式对应不同的css，也就是对应不同的类名（css）
        1、垂直布局 -> goods-list
        2、网格布局 -> goods-grid
        3、瀑布流布局 -> goods-waterfall
      3、实现不同的展现形式，本质上实现不同的css样式

      瀑布流效果实现思想
      1、创建商品列表的基本HTML和css ,让item相对于goods（div）进行排列
      2、生成不同高度的图片，撑起不同高度的item
      3、计算item的位置，以此达到瀑布流的布局效果
   -->
   <!--
     如果不允许 goods 单独滑动，那么就不添加 goods-scroll 类
    -->

    <!--
      商品排序：
        1、排序之后的数据源，用来在html中展示
        2、定义排序规则。（直接使用GppdsOption中数据源中的规则）
        3、定义排序的方法，根据 排序规则来修改对应排序
     -->

   <div class="goods" ref="goods" @scroll="onScrollChange" :class="[layoutClass, {'goods-scroll' : isScroll}]" :style="{height: goodsViewHeight}">
       <div class="goods-item" :class="layoutItemClass" ref="goodsItem" @click="onItemClick(item)" v-for="(item, index) in sortGoodsData" :key="index" :style="goodsItemStyles[index]">
           <!-- 图片 -->
           <img class="goods-item-img" :src="item.img" alt="" :style="imgStyles[index]">
            <!-- desc->description -->
            <div class="goods-item-desc">
                <p class="goods-item-desc-name text-line-2" :class="{'goods-item-desc-name-hint' : item.isHave}">
                    <!-- 是否为直营 -->
                    <direct v-if="item.isDirect"></direct>
                    <no-have v-if="!item.isHave"></no-have>
                    <!-- 是否有库存 -->
                    {{item.name}}
                </p>
                <div class="goods-item-desc-data">
                    <p class="goods-item-desc-data-price">￥{{item.price | priceValue}}</p>
                    <p class="goods-item-desc-data-volume">销量：{{item.volume}}</p>
                </div>
            </div>
       </div>
   </div>
</template>

<script>
import Direct from '@c/goods/Direct.vue'
import NoHave from '@c/goods/NoHave.vue'
export default {
  components: {
    Direct,
    NoHave
  },
  props: {
    /**
     * 在父元素中指定的展示形式
     * 1、垂直布局
     * 2、网格布局
     * 3、瀑布流布局
     */
    layoutType: {
      type: String,
      default: '1'
    },
    /**
     * 是否允许 goods 单独滑动
     * 默认允许 goods 单独滑动
     */
    isScroll: {
      type: Boolean,
      default: true
    },
    /**
     * 排序规则(以来 GoodsOption 数据源的id)
     * 1：默认
     * 1-2：价格由高到低
     * 1-3：销量由高到低
     * 2：有货优先
     * 3：直营优先
     */
    sort: {
      type: String,
      default: '1'
    }
  },
  data: function () {
    return {
      // 数据源
      dataSource: [],
      // 排序数据
      sortGoodsData: [],
      //   最大高度||最小高度
      MAX_IMG_HEIGHT: 230,
      MIN_IMG_HEIGHT: 178,
      //  图片样式集合
      imgStyles: [],
      // item margin
      ITEM_MARGIN_SIZE: 8,
      // item 样式集合
      goodsItemStyles: [],
      // goods组件的高度
      goodsViewHeight: '100%',
      // 不同展示形式下的类名
      // 1、垂直列表的展示形式（默认） -> goods-list & goods-list-item
      // 2、网格布局的展示形式 -> goods-grid & goods-grid-item
      layoutClass: 'goods-list',
      layoutItemClass: 'goods-list-item',
      // 滑动距离
      scrollTopValue: 0
    }
  },
  created: function () {
    this.initData()
  },
  activated: function () {
    // 定位页面滑动距离
    this.$refs.goods.scrollTop = this.scrollTopValue
  },
  methods: {
    /**
     * 获取数据
     */
    initData: function () {
      this.$http.get('/goods')
        .then(data => {
          this.dataSource = data.list
          // 数据排序
          this.setSortGoodsData()
          // 设置布局
          this.initLayout()
        })
    },
    /**
     * 商品排序
     */
    setSortGoodsData: function () {
      switch (this.sort) {
        // 默认
        case '1':
          // 深拷贝，不改变原数组
          this.sortGoodsData = this.dataSource.slice(0)
          break
        // 价格由高到低
        case '1-2':
          this.getsSortGoodsDataFromKey('price')
          break
        // 销量由高到低
        case '1-3':
          this.getsSortGoodsDataFromKey('volume')
          break
        // 有货优先
        case '2':
          this.getsSortGoodsDataFromKey('isHave')
          break
        // 直营优先
        case '3':
          this.getsSortGoodsDataFromKey('isDirect')
          break
      }
    },
    /**
     * 根据传入的 key 来进行排序
     */
    getsSortGoodsDataFromKey: function (key) {
      /**
       * sort 可以完成数组的数据排序
       * 当接收的值 为负数的时候， 表示 goods 排列在 goods2 之前
       * 当接收值为正数时， 表示 goods 排列在 goods2 之后
       * 接收值为0时，表示排序不变
       */
      this.sortGoodsData.sort((goods1, goods2) => {
        // 根据传入的 key 获取相对应的 value
        let v1 = ''
        let v2 = ''
        v1 = goods1[key]
        v2 = goods2[key]
        // 对 value 进行对比
        // boolean 类型的值 （有货优先和直营优先）
        if (typeof v1 === 'boolean') {
          if (v1) {
            return -1
          }
          if (v2) {
            return 1
          }
          return 0
        }
        // float 类型值得处理 （价格销量）
        if (parseFloat(v1) >= parseFloat(v2)) {
          return -1
        }
        return 1
      })
    },
    /**
     * 设置布局，为不同的 layoutType设定不同的展现形式
     * 1、初始化影响布局的数据
     *    1、goodsViewHeight -> 垂直布局、网格布局（100%）、瀑布流
     *    2、goodsItemStyle
     *    3、imgStyle
     * 2、为不同的layoutType设置不同的展示类
     */
    initLayout: function () {
      // 初试化数据
      this.goodsViewHeight = '100%'
      this.goodsItemStyles = []
      this.imgStyles = []
      // 为不同的layoutType设置不同的展示类
      switch (this.layoutType) {
        // 垂直列表
        case '1':
          this.layoutClass = 'goods-list'
          this.layoutItemClass = 'goods-list-item'
          break
        // 网格布局
        case '2':
          this.layoutClass = 'goods-grid'
          this.layoutItemClass = 'goods-grid-item'
          break
        // 瀑布流布局
        case '3':
          this.layoutClass = 'goods-waterfall'
          this.layoutItemClass = 'goods-waterfall-item'
          this.initImgStyle()
          // 调用创建瀑布流的方法(等到dom创建完成之后)
          this.$nextTick(() => {
            this.initWaterfall()
          })
          break
      }
    },
    /**
     * 返回随机的图片高度
     */
    imgHeight: function () {
      const result = Math.floor(Math.random() * (this.MAX_IMG_HEIGHT - this.MIN_IMG_HEIGHT) + this.MIN_IMG_HEIGHT)
      return result
    },
    /**
     * 根据随机的图片高度生成对应的图片数据
     */
    initImgStyle: function () {
      this.dataSource.forEach(item => {
        // 随机生成图片高度
        const imgHeight = this.imgHeight() + 'px'
        this.imgStyles.push({
          height: imgHeight
        })
      })
    },
    /**
     * 瀑布流布局
     * 1、获取到所有 item 元素
     * 2、遍历每一个item元素，得到每一个item的高度，加上一个margin高度
     * 3、创建两个变量： leftHeightTotal， rightHeightTotal分别表示左右两侧目前距离顶部的高度
     * 通过对左右两侧距离顶部的高度， 来确定 item 的放置位置
     *    如果左侧小于等于右侧高度的话 （leftHeightTotal <= rightHeightTotal） 那么item就应该放置在左侧，此时item距离左侧为0，距离顶部为当前的leftHeightTotal
     *    否则，item需要放置在右侧，此时item距离右侧为0，距离顶部为rightHeightTotal
     * 4、保存计算出的item 的所有样式，配置到item 上。
     * 5、item配置完成之后，对比左右两侧最大的高度，即最大高度为goods组件的高度
     */
    initWaterfall: function () {
      // 获取到所有的 item 元素
      // eslint-disable-next-line prefer-const
      let $goodsItems = this.$refs.goodsItem
      if (!$goodsItems) {
        return
      }
      let leftHeightTotal = 0
      let rightHeightTotal = 0
      $goodsItems.forEach(($el, index) => {
        // item 样式
        let goodsItemStyle = {}
        // eslint-disable-next-line prefer-const
        let elHeight = $el.clientHeight + this.ITEM_MARGIN_SIZE
        // 对比 左右两侧距离顶部的高度
        if (leftHeightTotal <= rightHeightTotal) {
          goodsItemStyle = {
            left: '0px',
            top: leftHeightTotal + 'px'
          }
          // 更新左侧距离顶部高度
          leftHeightTotal += elHeight
        } else {
          goodsItemStyle = {
            right: '0px',
            top: rightHeightTotal + 'px'
          }
          rightHeightTotal += elHeight
        }

        // 保存计算出的 item 所有样式，配置到 item 上
        this.goodsItemStyles.push(goodsItemStyle)
      })
      // 在不允许 Goods 单独滑动的时候
      if (!this.isScroll) {
        // 对比左右两侧最大的高度， 最大高度为 goods 组件的高度
        this.goodsViewHeight = (leftHeightTotal > rightHeightTotal ? leftHeightTotal : rightHeightTotal) + 'px'
      }
    },
    /**
     * 商品点击事件
     */
    onItemClick: function (item) {
      // 商品无库存不允许跳转
      if (!item.isHave) {
        alert('该商品无库存！')
        return
      }

      this.$router.push({
        name: 'goodsDetail',
        params: {
          routerType: 'push'
        },
        // 将传递数据附加到url上
        query: {
          goodsId: item.id
        }
      })
    },
    // 监听滑动事件
    onScrollChange: function ($event) {
      this.scrollTopValue = $event.target.scrollTop
    }
  },
  watch: {
    /**
     * 监听 layoutType
     */
    layoutType: function () {
      this.initLayout()
    },
    /**
     * 监听 sort 的改变
     */
    sort: function () {
      this.setSortGoodsData()
    }
  }
}
</script>

<style lang="scss" scoped>
    @import '@css/style.scss';

    .goods {
        background-color: $bgColor;

        &-scroll {
          overflow: hidden;
          overflow-y: auto;
        }

        &-item {
            background-color: white;
            padding: $marginSize;
            box-sizing: border-box;

            &-desc {
                width: 100%;

                &-name {
                    font-size: $infoSize;
                    line-height: px2rem(18);

                    &-hint {
                      color: $hintColor;
                    }
                }

                &-data {
                    width: 100%;
                    display: flex;
                    align-items: center;
                    justify-content: space-between;
                    margin-top: $marginSize;

                    &-price {
                        font-size: $titleSize;
                        color: $mainColor;
                        font-weight: 500;
                    }

                    &-volume {
                        font-size: $infoSize;
                        color: $hintColor;
                    }
                }
            }
        }
    }

    // 垂直列表
    .goods-list {
      &-item {
        display: flex;
        border-bottom: 1px solid $lineColor;

        .goods-item-img {
          width: px2rem(120);
          height: px2rem(120);
        }

        .goods-item-desc {
          display: flex;
          flex-direction: column;
          justify-content: space-between;
          padding: $marginSize;
        }
      }
    }

    // 网格布局
    .goods-grid {
      padding: $marginSize;
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;

      &-item {
        width: 49%;
        border-radius: $radiusSize;
        margin-bottom: $marginSize;

        .goods-item-img {
          width: 100%;
        }
      }
    }

    // 瀑布流
    .goods-waterfall {
        position: relative;
        margin: $marginSize;

        &-item {
            position: absolute;
            width: 49%;
            border-radius: $radiusSize;

            .goods-item-img {
                width: 100%;
            }
        }
    }

</style>
